#include "my_structs.h"
#include <vector>
#include <limits>
#include <algorithm>
#include "gmp.h"
#include "gmpxx.h"


std::istream& operator>>(std::istream& in, point_t& p)
{
	in >> p.x >> p.y;
	return in;
}

void init(mpq_t ax,mpq_t ay,mpq_t bx,mpq_t by,mpq_t cx,mpq_t cy)
{
	mpq_init(ax);
	mpq_init(bx);
	mpq_init(cx);
	mpq_init(ay);
	mpq_init(by);
	mpq_init(cy);
}

void clear(mpq_t ax,mpq_t ay,mpq_t bx,mpq_t by,mpq_t cx,mpq_t cy)
{
	mpq_clear(ax);
	mpq_clear(bx);
	mpq_clear(cx);
	mpq_clear(ay);
	mpq_clear(by);
	mpq_clear(cy);
}

int gmp_left_turn(point_t a, point_t b, point_t c)
{
	mpq_t ax,ay,bx,by,cx,cy;
	init(ax,ay,bx,by,cx,cy);

	mpq_set_d(ax,a.x);
	mpq_set_d(ay,a.y);
	mpq_set_d(bx,b.x);
	mpq_set_d(by,b.y);
	mpq_set_d(cx,c.x);
	mpq_set_d(cy,c.y);

	mpq_sub(bx,bx,ax);
	mpq_sub(by,by,ay);
	mpq_sub(cx,cx,ax);
	mpq_sub(cy,cy,ay);

	mpq_mul(ax,bx,cy);
	mpq_mul(ay,cx,by);

	mpq_sub(ax,ax,ay);

	int res = mpq_sgn(ax);
	clear(ax,ay,bx,by,cx,cy);

	return res;
}

int left_turn(point_t a, point_t b, point_t c)
{
	double imprecision = 4 * std::numeric_limits<double>::epsilon() * 
		(std::abs((b.x - a.x) * (c.y - a.y)) + std::abs((b.y - a.y) * (c.x - a.x)));
	double product = (b.x - a.x) * (c.y -a.y) - (b.y - a.y) * (c.x - a.x);

	if (product > imprecision) return 1;
	if (product < -imprecision) return -1;
	return gmp_left_turn(a,b,c);
}

bool point_t::operator<(const point_t& p) const
{
	if (x != p.x)
	{
		return x < p.x;
	}
	return y < p.y;
}

std::ostream& operator<<(std::ostream& out, const std::vector<point_t>& v)
{
	out << v.size() << "\n";
	std::cout.precision(30);
	for (auto i = v.begin(); i < v.end(); i++)
	{
		out << (*i).x << " " << (*i).y << "\n";
	}

	return out;
}

bool point_t::operator==(const point_t& p) const
{
	return (x == p.x) && (y == p.y);
}
